//
//  BigInt
//
//  Created by Caue W. on 2011-03-31.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//
package time.types.complex;
import time.Types;

/**
*  This is just a cross-target way to define a simple BigInt class.
*  No queries other than == is allowed, and only sum and sub is implemented
*  
*  TODO 1: first complete basic operations and test
*  TODO 2: have @AfterLoad and @BeforeSave operations to normalize
*  TODO: complete other operations, and add < and > support if possible
**/
@ValueType class BigInt 
{
	public static var ZERO = new BigInt([0], true);
	public static var ONE = new BigInt([1], true);
	
	static inline var MAX_BITS = #if neko 30 #else 31 #end;
	static inline var MASK = #if neko 0x3FFFFFFF #else 0x7FFFFFFF #end;
	static inline var SAFE_MUL10_VAL = #if neko 0x3FFFFFF #else 0x7FFFFFF #end;
	static var logTable8Bit(default, null):Array<Int>;
	
	static function __init__() : Void
	{
		logTable8Bit = [];
		var logTable8Bit = logTable8Bit;
		
		for (i in 0...256)
		{
			var v = 0;
			var i2 = i;
			while (i2 > 0)
			{
				v++;
				i2 = i2 >> 1;
			}
			
			logTable8Bit[i] = v;
		}
	}
	
	
	private var __s:Varchar<255>;
	private var positive:Bool;
	
	@Transient private var stringCalc:Bool;
	@Transient private var normalized:Bool;
	@Transient private var v:Array<Int>;
	
	private function new(v, p, ?n = false)
	{
		this.v = v.copy();
		this.positive = p;
		this.normalized = n;
	}
	
	//untested
	public static function fromString(s:String) : Null<BigInt>
	{
		var v = [];
		var p = true;
		var carry = 0;
		
		var val = 0;
		var i = s.length;
		while(i-- > 0)
		{
			if (carry != 0)
			{
				val += carry;
				carry = 0;
			}
			
			var c = StringTools.fastCodeAt(s, i);
			if (c == 0x2D && i == 0)
			{
				p = false;
				break;
			}
			
			if (c < 0x30 || c > 0x39) //invalid
				return null;
			
			val += (c - 0x30);
			
			if (val > SAFE_MUL10_VAL /*will cause overflow*/)
			{
				v.push(val);
				val = 0;
			} else {
				val *= 10;
			}
			
		}
		
		if (val != 0)
			v.push(val);
		
		var b = new BigInt(v, p);
		b.normalize();
		
		return b;
	}
	
	
	
	private inline function log(i:Int) : Int
	{
		var tt = i >> 16;
		var t;
		
		return if (tt != 0)
		{
		  ( (t = tt >> 8) != 0) ? 24 + logTable8Bit[t] : 16 + logTable8Bit[tt];
		}
		else 
		{
		  ( (t = i >> 8) != 0) ? 8 + logTable8Bit[t] : logTable8Bit[i];
		}
	}
	
	public function add(b:BigInt) : BigInt
	{
		return null;
	}
	
	private function normalize() : Void
	{
		if (normalized && v != null)
			return;
		
		if (v == null)
		{
			if (__s == null)
				throw "assert";
			var b = fromString(__s);
			this.v = b.v;
			this.normalized = stringCalc = true;
			
			return;
		} else {
			
		}
	}
	
	//TODO complete here ...
	
	
	
	
}